#pragma once

#include <iostream>
#include <string>
#include <jsoncpp/json/json.h>
//制定协议
// 我们要实现的是：输入：_x _oper _y  输出：result（flag）
// 请求
class Requst
{
public:
    Requst()
    {
        _x = _y = _oper = 0;
    }
    // 序列化对象
    bool Serialize(std::string *out)
    {
        Json::Value root;
        root["x"] = _x;
        root["y"] = _y;
        root["oper"] = _oper;
        Json::StyledWriter writer;
        *out = writer.write(root);
        if (out->empty())
            return false;
        return true;
    }
    // 反序列化对象
    bool Deserialize(std::string &in)
    {
        Json::Reader reader;
        Json::Value root;
        bool ret = reader.parse(in, root);
        if (!ret)
            return false;

        _x = root["x"].asInt();
        _y = root["y"].asInt();
        _oper = root["oper"].asInt();

        return true;
    }
    int X()
    {
        return _x;
    }
    int Y()
    {
        return _y;
    }
    int Oper()
    {
        return _oper;
    }
    ~Requst()
    {
    }

public:
    int _x;
    int _y;
    char _oper;
};

// 应答
class Response
{
public:
    Response()
    {
        _result = _flag = 0;
    }
    // 序列化对象
    bool Serialize(std::string *out)
    {
        Json::Value root;
        root["result"] = _result;
        root["flag"] = _flag;
        Json::StyledWriter writer;
        *out = writer.write(root);
        if (out->empty())
            return false;
        return true;
    }
    // 反序列化
    bool Deserialize(std::string &in)
    {
        Json::Reader reader;
        Json::Value root;
        bool ret = reader.parse(in, root);
        if (!ret)
            return false;
        _result = root["result"].asInt();
        _flag = root["flag"].asInt();

        return true;
    }
    void SetResult(int r)
    {
        _result = r;
    }
    void SetCode(int f)
    {
        _flag = f;
    }
    void Print()
    {
        std::cout << _result << "[" << _flag << "]" << std::endl;
    }
    ~Response()
    {
    }

public:
    int _result;
    // 用于判断得出的结果是否可靠，假设是除零就不是可靠答案
    int _flag;
};

static const std::string sep = "\r\n";

class Protocol
{
public:
    // 打包，以下面这种方式进行打包，len表示需要打包数据报长度
    //  jsonstr -> len\r\njsonstr\r\n
    static std::string Package(const std::string &jsonstr)
    {
        // 判断是否为空，是空返回空字符串
        if (jsonstr.empty())
            return std::string();
        // 计算数据报长度
        std::string json_length = std::to_string(jsonstr.size());
        // len\r\njsonstr\r\n
        return (json_length + sep + jsonstr + sep);
    }

    static bool DigitSafeCheck(const std::string str)
    {
        for (int i = 0; i < str.size(); i++)
        {
            if (!(str[i] >= '0' && str[i] <= '9'))
                return false;
        }
        return true;
    }

    // 解包
    //  origin_str: 从网络中读取上来的字符串,输入输出
    //  package: 输出参数，如果有完整的json报文，就返回
    static int Unpack(std::string &origin_str, std::string *package)
    {
        if (!package)
            return 0;
        auto pos = origin_str.find(sep);
        if (pos == std::string::npos)
            return 0;
        // 走到这里就说明至少得到了一个数据报的有效长度数
        std::string len_str = origin_str.substr(0, pos);
        // 安全检查（每个位都是在0~9之前的）
        if(!DigitSafeCheck(len_str))
            return -1;
        int digit_len = std::stoi(len_str);
        //求出数据报总长度
        int target_len = len_str.size() + digit_len + 2*sep.size();
        if(origin_str.size() < target_len)
            return 0;

        //走到这里就一定得到了一个完整的数据报
        //取出有效报文
        *package = origin_str.substr(pos + sep.size(), digit_len);
        //将报文取出后，删除该报文
        origin_str.erase(0, target_len);

        return package->size();
    }
};